package cn.tlb.gl.face20_3d;

import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import static javax.microedition.khronos.opengles.GL10.GL_COLOR_ARRAY;
import static javax.microedition.khronos.opengles.GL10.GL_COLOR_BUFFER_BIT;
import static javax.microedition.khronos.opengles.GL10.GL_DEPTH_BUFFER_BIT;
import static javax.microedition.khronos.opengles.GL10.GL_FIXED;
import static javax.microedition.khronos.opengles.GL10.GL_FLOAT;
import static javax.microedition.khronos.opengles.GL10.GL_TRIANGLE_STRIP;
import static javax.microedition.khronos.opengles.GL10.GL_UNSIGNED_BYTE;
import static javax.microedition.khronos.opengles.GL10.GL_VERTEX_ARRAY;

/**
 * 二十面体
 */
public class Face20_3D_Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        GLSurfaceView mGlSurfaceView = new GLSurfaceView(this);
        mGlSurfaceView.setRenderer(new Face20Renderer());
        setContentView(mGlSurfaceView);
    }
    private float rotateX;
    private float rotateY;
    private float touchX;
    private float touchY;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch(event.getAction()){
            case MotionEvent.ACTION_DOWN:
                touchX = event.getX();
                touchY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                rotateX += (event.getX()-touchX)/20;
                rotateY += ((event.getY()-touchY))/20;
                break;
            default:
                break;
        }
        return true;
    }

    private class Face20Renderer implements GLSurfaceView.Renderer{

        private float rot = 0.0f;

        private final float vertices[]= {
                0, -0.525731f, 0.850651f,             // vertices[0]
                0.850651f, 0, 0.525731f,              // vertices[1]
                0.850651f, 0, -0.525731f,             // vertices[2]
                -0.850651f, 0, -0.525731f,            // vertices[3]
                -0.850651f, 0, 0.525731f,             // vertices[4]
                -0.525731f, 0.850651f, 0,             // vertices[5]
                0.525731f, 0.850651f, 0,              // vertices[6]
                0.525731f, -0.850651f, 0,             // vertices[7]
                -0.525731f, -0.850651f, 0,            // vertices[8]
                0, -0.525731f, -0.850651f,            // vertices[9]
                0, 0.525731f, -0.850651f,             // vertices[10]
                0, 0.525731f, 0.850651f               // vertices[11]
        };

        private final int colors[] = {
                0xFFFF, 0, 0, 0xFFFF,
                0xFFFF, 0x7777, 0, 0xFFFF,
                0xFFFF, 0xFFFF, 0, 0xFFFF,
                0x7777, 0xFFFF, 0, 0xFFFF,
                0, 0xFFFF, 0, 0xFFFF,
                0, 0xFFFF, 0x7777, 0xFFFF,
                0, 0xFFFF, 0xFFFF, 0xFFFF,
                0, 0x7777, 0xFFFF, 0xFFFF,
                0, 0, 0xFFFF, 0xFFFF,
                0x7777, 0, 0xFFFF, 0xFFFF,
                0xFFFF, 0, 0xFFFF, 0xFFFF,
                0xFFFF, 0, 0x7777, 0xFFFF
        };

        private final byte icosahedronFaces[] = {
                1, 2, 6,
                1, 7, 2,
                3, 4, 5,
                4, 3, 8,
                6, 5, 11,
                5, 6, 10,
                9, 10, 2,
                10, 9, 3,
                7, 8, 9,
                8, 7, 0,
                11, 0, 1,
                0, 11, 4,
                6, 2, 10,
                1, 6, 11,
                3, 5, 10,
                5, 4, 11,
                2, 7, 9,
                7, 1, 0,
                3, 9, 8,
                4, 8, 0
        };
        private FloatBuffer verticesBuffer = array2FloatBuffer(vertices);
        private IntBuffer colorsBuffer = array2IntBuffer(colors);
        private ByteBuffer icosahedronFacesBuffer = ByteBuffer.wrap(icosahedronFaces);

        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            gl.glDisable(GL10.GL_DITHER);
            gl.glShadeModel(GL10.GL_SMOOTH);

            gl.glClearColor(0, 0, 0, 0);
            gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
            gl.glEnable(GL10.GL_DEPTH_TEST);
            gl.glDepthFunc(GL10.GL_LEQUAL);
        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            gl.glViewport(0, 0, width, height);
            gl.glMatrixMode(GL10.GL_PROJECTION);
            gl.glLoadIdentity();
            float ratio = (float)width/height;
            gl.glFrustumf(-2, 2, -2, 2, 1, 10);
        }

        @Override
        public void onDrawFrame(GL10 gl) {
            gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glEnableClientState(GL_VERTEX_ARRAY);
            gl.glEnableClientState(GL_COLOR_ARRAY);
            gl.glLoadIdentity();

            gl.glTranslatef(0.0f, 0.0f, -2.0f);
            gl.glRotatef(rotateX, 0, .2f, 0);
            gl.glRotatef(rotateY, 0.2f, 0, 0);
            gl.glVertexPointer(3, GL_FLOAT, 0, verticesBuffer);
            gl.glColorPointer(4, GL_FIXED, 0, colorsBuffer);
            gl.glDrawElements(GL_TRIANGLE_STRIP, icosahedronFacesBuffer.remaining(), GL_UNSIGNED_BYTE, icosahedronFacesBuffer);

            gl.glFinish();
            gl.glDisableClientState(GL_VERTEX_ARRAY);
            gl.glDisableClientState(GL_COLOR_ARRAY);
        }

        private FloatBuffer array2FloatBuffer(float fs[]){
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(fs.length * 4);
            byteBuffer.order(ByteOrder.nativeOrder());
            FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
            floatBuffer.put(fs);
            floatBuffer.position(0);
            return floatBuffer;
        }

        private IntBuffer array2IntBuffer(int ints[]){
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(ints.length*4);
            byteBuffer.order(ByteOrder.nativeOrder());
            IntBuffer intBuffer = byteBuffer.asIntBuffer();
            intBuffer.put(ints);
            intBuffer.position(0);
            return intBuffer;
        }
    }
}
